<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>随机数生成器(RNGs) - The Rust Rand Book</title>
        
        


        <!-- Custom HTML head -->
        


        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="Extended documentation for Rust&#x27;s Rand lib">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        
        <link rel="icon" href="favicon.svg">
        
        
        <link rel="shortcut icon" href="favicon.png">
        
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        
        <link rel="stylesheet" href="fonts/fonts.css">
        

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        

        
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="intro.html">介绍</a></li><li class="chapter-item expanded "><a href="guide-start.html"><strong aria-hidden="true">1.</strong> 入门指南</a></li><li class="chapter-item expanded "><a href="crates.html"><strong aria-hidden="true">2.</strong> crate 和特性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="crates-rand.html"><strong aria-hidden="true">2.1.</strong> 随机加密(co)</a></li><li class="chapter-item expanded "><a href="crates-gen.html"><strong aria-hidden="true">2.2.</strong> 随机信号生成器</a></li></ol></li><li class="chapter-item expanded "><a href="guide.html"><strong aria-hidden="true">3.</strong> 指南</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="guide-data.html"><strong aria-hidden="true">3.1.</strong> 随机数据</a></li><li class="chapter-item expanded "><a href="guide-gen.html"><strong aria-hidden="true">3.2.</strong> 生成器类型</a></li><li class="chapter-item expanded "><a href="guide-rngs.html" class="active"><strong aria-hidden="true">3.3.</strong> 随机数生成器(RNGs)</a></li><li class="chapter-item expanded "><a href="guide-seeding.html"><strong aria-hidden="true">3.4.</strong> 为随机数生成器置种</a></li><li class="chapter-item expanded "><a href="guide-values.html"><strong aria-hidden="true">3.5.</strong> 随机值</a></li><li class="chapter-item expanded "><a href="guide-dist.html"><strong aria-hidden="true">3.6.</strong> 各种分布方式</a></li><li class="chapter-item expanded "><a href="guide-seq.html"><strong aria-hidden="true">3.7.</strong> 序列</a></li><li class="chapter-item expanded "><a href="guide-err.html"><strong aria-hidden="true">3.8.</strong> 错误处理</a></li></ol></li><li class="chapter-item expanded "><a href="portability.html"><strong aria-hidden="true">4.</strong> 可移植性</a></li><li class="chapter-item expanded "><a href="update.html"><strong aria-hidden="true">5.</strong> 更新</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="update-0.5.html"><strong aria-hidden="true">5.1.</strong> 更新到 0.5</a></li><li class="chapter-item expanded "><a href="update-0.6.html"><strong aria-hidden="true">5.2.</strong> 更新到 0.6</a></li><li class="chapter-item expanded "><a href="update-0.7.html"><strong aria-hidden="true">5.3.</strong> 更新到 0.7</a></li></ol></li><li class="chapter-item expanded "><a href="contributing.html"><strong aria-hidden="true">6.</strong> 贡献</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="contrib-doc.html"><strong aria-hidden="true">6.1.</strong> 文档</a></li><li class="chapter-item expanded "><a href="contrib-scope.html"><strong aria-hidden="true">6.2.</strong> Scope</a></li><li class="chapter-item expanded "><a href="contrib-test.html"><strong aria-hidden="true">6.3.</strong> 测试</a></li><li class="chapter-item expanded "><a href="contrib-bench.html"><strong aria-hidden="true">6.4.</strong> 基准</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                        
                    </div>

                    <h1 class="menu-title">The Rust Rand Book</h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        
                    </div>
                </div>

                
                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1><a class="header" href="#our-rngs" id="our-rngs">Our RNGs</a></h1>
<h1><a class="header" href="#随机数生成器" id="随机数生成器">随机数生成器</a></h1>
<blockquote>
<p><a href="https://github.com/rust-random/book/blob/master/src/guide-gen.md">guide-gen.md</a><br />
commit: c5de1dc9ba6f5852023432fea3f988da7bfecefc <br />
本章译文最后维护日期：2020-11-28</p>
</blockquote>
<p>RNG有很多种，各有不同的取舍。Rand 在 <a href="https://rust-random.github.io/rand/rand/rngs/index.html"><code>rngs</code>模块</a>中提供了一些方便趁手的生成器。一般情况下只使用 <a href="https://rust-random.github.io/rand/rand/fn.thread_rng.html"><code>thread_rng</code></a> 就可以了，这个函数会在线程的局部内存中自动初始化一个RNG，并返回一个RNG的引用。它速度快，质量好，而且（据我们所知）加密安全。</p>
<p>本节内容：</p>
<ol>
<li><a href="#the-generators">生成器</a></li>
<li><a href="#performance">性能和尺寸(size)</a></li>
<li><a href="#quality">Quality and cycle length</a></li>
<li><a href="#security">安全性</a></li>
<li><a href="#extra-features">额外功能</a></li>
<li><a href="#further-reading">延伸阅读</a></li>
</ol>
<h1><a class="header" href="#the-generators" id="the-generators">The generators</a></h1>
<h1><a class="header" href="#生成器" id="生成器">生成器</a></h1>
<h2><a class="header" href="#basic-pseudo-random-number-generators-prngs" id="basic-pseudo-random-number-generators-prngs">Basic pseudo-random number generators (PRNGs)</a></h2>
<h2><a class="header" href="#初级伪随机数生成器" id="初级伪随机数生成器">初级伪随机数生成器</a></h2>
<p>“标准”非加密型PRNG的目标通常是在简单性、质量、内存使用和性能之间找到一个良好的平衡。非加密生成器比加密生成器出现的早，并且在某些方面已经被加密生成器淘汰，不过，非加密生成器也有一些优势：状态范围小、初始化快、简单、可使用低功耗的嵌入式CPU。（然而，并非所有的非加密型PRNG都提供了这些好处，例如，尽管很容易预测，但梅森旋转(Mersenne Twister/MT)算法的状态却非常大）。</p>
<p>这些（初级伪随机）算法对蒙特卡洛模拟(Monte Carlo simulations)非常重要；这些算法也适用于随机算法和游戏中，这些场景下的可预测性不是核心问题。（注意，对于赌博游戏，可预测性可能是一个问题，建议使用加密型PRNG。）</p>
<p>Rand项目提供了几个非加密型PRNG。
下面总结了其中的一些。详情可以参考 <a href="http://www.pcg-random.org/">pcg-random</a> 和 <a href="http://xoshiro.di.unimi.it/">xoshiro</a> 网站。</p>
<table><thead><tr><th>名称</th><th>全称</th><th>性能表现</th><th>占用内存</th><th>质量评价</th><th>周期长度</th><th>特性</th></tr></thead><tbody>
<tr><td><a href="https://rust-random.github.io/rand/rand/rngs/struct.SmallRng.html"><code>SmallRng</code></a></td><td>(未指定)</td><td>7 GB/s</td><td>16 字节</td><td>★★★☆☆</td><td>≥ <code>u32</code> * 2<sup>64</sup></td><td>不能被移植</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg32.html"><code>Pcg32</code></a></td><td>PCG XSH RR 64/32 (LCG)</td><td>3 GB/s</td><td>16 字节</td><td>★★★☆☆</td><td><code>u32</code> * 2<sup>64</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg64.html"><code>Pcg64</code></a></td><td>PCG XSL 128/64 (LCG)</td><td>4 GB/s</td><td>32 字节</td><td>★★★☆☆</td><td><code>u64</code> * 2<sup>128</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_pcg/type.Pcg64Mcg.html"><code>Pcg64Mcg</code></a></td><td>PCG XSL 128/64 (MCG)</td><td>7 GB/s</td><td>16 字节</td><td>★★★☆☆</td><td><code>u64</code> * 2<sup>126</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xorshift/struct.XorShiftRng.html"><code>XorShiftRng</code></a></td><td>Xorshift 32/128</td><td>5 GB/s</td><td>16 字节</td><td>★☆☆☆☆</td><td><code>u32</code> * 2<sup>128</sup> - 1</td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xoshiro/struct.Xoshiro256PlusPlus.html"><code>Xoshiro256PlusPlus</code></a></td><td>Xoshiro256++</td><td>7 GB/s</td><td>32 字节</td><td>★★★☆☆</td><td><code>u64</code> * 2<sup>256</sup> - 1</td><td>jump-ahead</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xoshiro/struct.Xoshiro256Plus.html"><code>Xoshiro256Plus</code></a></td><td>Xoshiro256+</td><td>8 GB/s</td><td>32 字节</td><td>★★☆☆☆</td><td><code>u64</code> * 2<sup>256</sup> - 1</td><td>jump-ahead</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_xoshiro/struct.SplitMix64.html"><code>SplitMix64</code></a></td><td>splitmix64</td><td>8 GB/s</td><td>8 字节</td><td>★☆☆☆☆</td><td><code>u64</code> * 2<sup>64</sup></td><td>—</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand/rngs/mock/struct.StepRng.html"><code>StepRng</code></a></td><td>counter</td><td>51 GB/s</td><td>16 字节</td><td>☆☆☆☆☆</td><td><code>u64</code> * 2<sup>64</sup></td><td>—</td></tr>
</tbody></table>
<p>这里基于 3.4GHz Haswell CPU，粗略地测量了 <code>u64</code>类型的输出的性能（请注意，这可能因具体测试的应用而有较大的结果差异；通常加密型RNG使用字节序列输出效果更好）。质量评价基于内部算法和可观察到的缺陷，大致如下：</p>
<ul>
<li>★☆☆☆☆ = 适合简单的应用程序，但有明显的缺陷</li>
<li>★★☆☆☆ = 在大多数测试中表现良好，存在一些问题</li>
<li>★★★☆☆ = 良好的性能和算法，没有重大问题</li>
<li>★★★★★ = 加密级质量(cryptographic quality)</li>
</ul>
<h2><a class="header" href="#cryptographically-secure-pseudo-random-number-generators-csprngs" id="cryptographically-secure-pseudo-random-number-generators-csprngs">Cryptographically secure pseudo-random number generators (CSPRNGs)</a></h2>
<h2><a class="header" href="#加密安全伪随机数生成器csprng" id="加密安全伪随机数生成器csprng">加密安全伪随机数生成器(CSPRNG)</a></h2>
<p>CSPRNG比初级PRNG要求要高。首要考虑的是安全性。性能和简洁性也很重要，但通常CSPRNG比常规PRNG更复杂、更慢。对CSPRNG来说，质量评级不再是一个问题，因为CSPRNG的要求是输出基本上与真正的随机性没有区别，因为任何偏差或相关性都可能使输出更具有可预测性。</p>
<p>CSPRNG与密码学有着密切的关系。通过对计数器进行加密，任何分组密码都可以转换为CSPRNG。流密码基本上是一个CSPRNG和一个组合操作，通常是异或。这意味着我们可以很容易地将任何流密码用作CSPRNG。</p>
<p>这个库提供了以下CSPRNG。我们不能保证任何安全要求。由于CSPRNG可能没有可观察到的缺陷，此表省略了前表中的“质量评价”列。</p>
<table><thead><tr><th>名称</th><th>全称</th><th>性能</th><th>初始化速度</th><th>占用内存</th><th>安全性 (可预测性)</th><th>前向安全性(forward secrecy)</th></tr></thead><tbody>
<tr><td><a href="https://rust-random.github.io/rand/rand/rngs/struct.StdRng.html"><code>StdRng</code></a></td><td>(未指定)</td><td>1.5 GB/s</td><td>快</td><td>136 字节</td><td>广受信任</td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaCha20Rng.html"><code>ChaCha20Rng</code></a></td><td>ChaCha20</td><td>1.8 GB/s</td><td>快</td><td>136 字节</td><td><a href="https://tools.ietf.org/html/rfc7539#section-1">严格分析</a></td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaCha8Rng.html"><code>ChaCha8Rng</code></a></td><td>ChaCha8</td><td>2.2 GB/s</td><td>快</td><td>136 字节</td><td>安全边际较小</td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_hc/struct.Hc128Rng.html"><code>Hc128Rng</code></a></td><td>HC-128</td><td>2.1 GB/s</td><td>慢</td><td>4176 字节</td><td><a href="http://www.ecrypt.eu.org/stream/">eSTREAM推荐</a></td><td>无</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_isaac/isaac/struct.IsaacRng.html"><code>IsaacRng</code></a></td><td>ISAAC</td><td>1.1 GB/s</td><td>慢</td><td>2072 字节</td><td><a href="https://burtleburtle.net/bob/rand/isaacafa.html">未知</a></td><td>未知</td></tr>
<tr><td><a href="https://rust-random.github.io/rand/rand_isaac/isaac64/struct.Isaac64Rng.html"><code>Isaac64Rng</code></a></td><td>ISAAC-64</td><td>2.2 GB/s</td><td>慢</td><td>4136 字节</td><td>未知</td><td>未知</td></tr>
</tbody></table>
<p>需要指出的是，ISAAC生成器只是出于历史原因才被包括在内的，它们从一开始就使用了 Rust语言。它们具有高质量的输出，并且没有已知的攻击，但是它们很少受到加密专家的关注。</p>
<h1><a class="header" href="#notes-on-generators" id="notes-on-generators">Notes on generators</a></h1>
<h1><a class="header" href="#各种生成器的关注点" id="各种生成器的关注点">各种生成器的关注点</a></h1>
<h2><a class="header" href="#performance" id="performance">Performance</a></h2>
<h2><a class="header" href="#性能" id="性能">性能</a></h2>
<p>首先，必须说大多数PRNG都非常快，很少会成为性能瓶颈。</p>
<p>初级PRNG的性能有点微妙。它很大程度上取决于CPU架构（32bit vs. 64bit）、内联以及可用寄存器的数量。由于内联和其他寄存器的使用，这通常会导致性能还受到其周围代码的影响。</p>
<p>在考虑为性能而选择PRNG时需要注意，由于PRNG与其周围代码之间的交互作用、对CPU架构的依赖以及请求的数据大小的影响，那对自己的应用程序进行基准测试就显得非常重要。正因为如此，我们在这里不包括性能数字，而只是一个定性评级。</p>
<p>CSPRNGs略有不同，因为它们通常在缓存中生成一个输出块，并从缓存中提取输出。这使得它们具有良好的缓冲性能，并减少或完全消除了周围代码对其性能的影响。</p>
<h3><a class="header" href="#worst-case-performance" id="worst-case-performance">Worst-case performance</a></h3>
<h3><a class="header" href="#最坏情况下的性能" id="最坏情况下的性能">最坏情况下的性能</a></h3>
<p>简单的PRNG通常根据需要生成每个随机值。相比之下，CSPRNG通常一次生成整个块，然后从缓存中读取，直到缓存读完，这使得它们在提取少量随机数据时性能不太一致。</p>
<h3><a class="header" href="#memory-usage" id="memory-usage">Memory usage</a></h3>
<h3><a class="header" href="#内存使用量" id="内存使用量">内存使用量</a></h3>
<p>简单的PRNG通常使用很少的内存，通常只有几个字(word)，其中<em>字</em>通常是 <code>u32</code> 或 <code>u64</code>。但并非所有非加密型PRNG都是如此，例如历史上流行的Mersenne Twister MT19937算法需要 2.5 kB 的状态。</p>
<p>CSPRNG通常需要更多的内存；由于建议种子大小至少为192-bit，而且算法可能需要更多的 bit，256-bit大概是最小的安全大小。在实际实践中，CSPRNG往往使用更多，<a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaChaRng.html"><code>ChaChaRng</code></a> 的内存使用量相对较小，只有 136个字节的状态。</p>
<h3><a class="header" href="#initialization-time" id="initialization-time">Initialization time</a></h3>
<h3><a class="header" href="#初始化时间" id="初始化时间">初始化时间</a></h3>
<p>初始化新生成器所需的时间差别很大。许多简单PRNG，甚至一些CSPRNG（包括 <a href="https://rust-random.github.io/rand/rand_chacha/struct.ChaChaRng.html"><code>ChaChaRng</code></a>）只需要将种子值和一些常量复制进它们的状态里，就可以很快地构造出来。相比之下，具有大状态的CSPRNG则需要昂贵的密钥扩展。</p>
<h2><a class="header" href="#quality" id="quality">Quality</a></h2>
<h2><a class="header" href="#质量评价" id="质量评价">质量评价</a></h2>
<p>许多初级PRNG只不过是一些位运算和算术运算。它们的简单性提供了良好的性能，但也意味着在生成的随机数流中隐藏了一些小的规律。</p>
<p>这些隐藏的规律有多大的负作用？这很难说，取决于如何使用RNG。如果随机数和使用它们的算法之间碰巧存在相关性，结果可能是错误的或误导性的。</p>
<p>如果一个随机数生成器能在尽可能多的应用中给出正确的结果，那么它就可以被认为是好的。
PRNG算法的质量可以在一定程度上进行分析评估，以确定循环长度(cycle length)，并排除一些相关性。此外，还有一些经验测试套件，旨在测试PRNG在各种可能用途上的表现，其中最新和最完整的是 <a href="http://simul.iro.umontreal.ca/testu01/tu01.html">TestU01</a> 和 <a href="http://pracrand.sourceforge.net/">PractRand</a>。</p>
<p>CSPRNG往往更复杂，并且有一个明确的要求是不可预测的。这意味着各个输出值之间一定没有明显的相关性。</p>
<h3><a class="header" href="#quality-stars" id="quality-stars">Quality stars:</a></h3>
<h3><a class="header" href="#质量评星等级" id="质量评星等级">质量评星等级</a></h3>
<p>对于大多数非加密应用，3星或更高的PRNG应该足够好了。对于典型的应用程序和游戏来说，1星或 2星可能已经足够了，但并不所有的算法在所有的场景下都能很好的运行。</p>
<h3><a class="header" href="#period" id="period">Period</a></h3>
<h3><a class="header" href="#周期" id="周期">周期</a></h3>
<p>PRNG的<em>周期</em>或*循环长度(cycle length)*是可以生成的值的数目，之后它开始重复相同的随机数流。许多PRNG都有一个固定的大小周期，而对于另一些（“混沌随机数生成器”），其周期长度可能取决于种子，并且允许存在短周期。</p>
<p>注意，长周期并不意味着高质量（例如，通过 <code>u128</code> 值的计数器提供了相当长的周期）。当然，短周期也可能是一个问题，特别是在同时使用多个RNG时。
一般来说，我们建议周期至少为 2<sup>128</sup>。（或者，一个至少为 2<sup>64</sup> 的较短周期，并且支持多个流的PRNG可能就足够了。但请注意，在PCG的情况下，其流是密切相关的。）<!-- tobocheck --></p>
<p><em>避免重用值！</em>
在今天的硬件上，一个循环长度虽然<em>只有</em> 2<sup>64</sup> 的快速RNG仍然可以在一个循环用尽之前连续使用几个世纪。但是，当多个RNG并行使用时（每个rng都有一个唯一的种子），它们生成的输出序列之间有很大的几率会重叠。
对于具有<em>大</em>周期 <code>P</code> 的 <code>n</code>个独立生成器，并且每个生成器生成的序列的长度为 <code>L</code>，当 <code>nL / P</code> 接近于零时，序列之间的任何重叠概率可以近似为 <code>Ln² / P</code> 。有关这个主题的更多信息，请参见 <a href="http://prng.di.unimi.it/#remarks">Xoshiro的作者的这些评论</a>。</p>
<p><em>碰撞和生日悖论!</em>
对于输出与状态相等的生成器，建议不要使用超过 <code>√P</code> 的输出。对<code>kw</code>-bit 长度的状态和 <code>w</code>-bit 长度的生成器的总的原则是确保 <code>kL² &lt; P</code>。这一要求源于<em>广义生日问题</em>，即在重复发生的概率至少为一半之前，从一组大小为 <code>d = 2^w</code> 的样本集合中可以提取多少个无偏样本。
注意，对于 <code>kL² &gt; P</code> ，具有 <code>kw</code>维等分布的生成器<em>不能</em>生成预期的重复样本数，但是没有此属性的生成器<em>也</em>不能保证生成预期的重复样本数。</p>
<h2><a class="header" href="#security" id="security">Security</a></h2>
<h2><a class="header" href="#安全性" id="安全性">安全性</a></h2>
<h3><a class="header" href="#predictability" id="predictability">Predictability</a></h3>
<h3><a class="header" href="#可预测性" id="可预测性">可预测性</a></h3>
<p>从任何PRNG的上下文中，可以提出这样的问题*给出PRNG之前的一些输出，是否有可能预测下一个输出值？*在任何可能有攻击者的情况下，这是一个重要的问题。</p>
<p>常规的PRNG往往是可预测的，尽管困难程度各不相同。在某些情况下，预测不要太容易哦，例如简单的 Xorshift算法会不加任何修改的输出其状态的一部分，对它们的预测就像从四个 <code>u32</code> 输出中植入一个新的Xorshift生成器一样简单。其他生成器，如<a href="http://www.pcg-random.org/predictability.html">PCG</a>和 截断Xorshift算法 要难预测一些，但也不超出普通数学和台式机的运算能力范围之外。</p>
<p>CSPRNG必须提供的基本安全要求是预测输出的不可行性。这一要求被形式化为<a href="https://en.wikipedia.org/wiki/Next-bit_test">下一位测试(next-bit test)</a>；这可大致描述为：给定随机序列的前 <em>k</em>位，如果没有算法能够使用合理的计算能力预测下一位，则序列满足下一位测试。</p>
<p><em>一些</em>CSPRNG提供了另一种安全性是前向保密:在CSPRNG的状态在某些时候被泄露的情况下，重建之前的状态或输出是不可行的。注意，许多CSPRNG在其通常的配置中<em>没有</em>实现前向保密。</p>
<p>验证算法的安全性声明是一个<em>困难的问题</em>，所以我们无法为本项目使用或推荐的算法的安全性提供任何保证。我们建议您向<a href="https://www.nist.gov/">NIST</a>研究所和<a href="http://www.ecrypt.eu.org/">ECRYPT</a>网络寻求建议。</p>
<h3><a class="header" href="#state-and-seeding" id="state-and-seeding">State and seeding</a></h3>
<h3><a class="header" href="#设定状态和种子" id="设定状态和种子">设定状态和种子</a></h3>
<p>值得注意的是，CSPRNG的安全性完全依赖于使用一个安全的随机密钥来置种(seeding)。如果密钥是已知的或可猜测的，CSPRNG的所有输出都很容易猜测。这意味着种子应该来自可信的源；通常是操作系统或另一个CSPRNG。我们用来置种(seeding)的辅助trait，<a href="https://rust-random.github.io/rand/rand/trait.FromEntropy.html"><code>FromEntropy</code></a>，及其使用的源（<a href="https://rust-random.github.io/rand/rand/rngs/struct.EntropyRng.html"><code>EntropyRng</code></a>）应该是安全的。此外，<a href="https://rust-random.github.io/rand/rand/rngs/struct.ThreadRng.html"><code>ThreadRng</code></a> 是一个CSPRNG，因此它可以用此 trait 来置种(seeding)（尽管对于安全应用程序，应该首选新鲜/外部熵来作文种子来源）。</p>
<p>此外，很明显，CSPRNG的内部状态必须保密。考虑到这一点，我们的实现不提供对其大多数内部状态的直接访问，<code>Debug</code>实现也不打印任何内部状态。这并不能完全保护CSPRNG的状态；同一进程中的代码可能会读取这个内存（为了方便起见，我们允许克隆和序列化CSPRNG）。再有，一个正在运行的进程可能被操作系统 fork，这样可能会给两个进程都留下同一个生成器的副本。</p>
<h3><a class="header" href="#not-a-crypto-library" id="not-a-crypto-library">Not a crypto library</a></h3>
<h3><a class="header" href="#注意-rand-不是一个密码学库" id="注意-rand-不是一个密码学库">注意 Rand 不是一个密码学库</a></h3>
<p>需要强调的是，Rand 不是一个密码学库；尽管 Rand 确实采取了一些措施来提供安全的随机数，但它没有全部采取密码学所推荐的所有措施。此外，加密和身份验证等加密过程非常复杂，必须非常小心地实现，以避免漏洞，和抵御已知的攻击。因此，建议专业项目尽可能使用专用的密码学库，例如 <a href="https://crates.io/crates/openssl">openssl</a>、<a href="https://crates.io/crates/ring">ring</a> 和 <a href="https://github.com/RustCrypto">RustCrypto库</a>。</p>
<h2><a class="header" href="#extra-features" id="extra-features">Extra features</a></h2>
<h2><a class="header" href="#额外功能" id="额外功能">额外功能</a></h2>
<p>有一些PRNG还提供了额外的功能</p>
<ul>
<li>支持多流来助力并行任务。</li>
<li>在随机数流中跳转或搜索的能力；在长周期的条件下，可以作为流的替代。</li>
</ul>
<h2><a class="header" href="#further-reading" id="further-reading">Further reading</a></h2>
<h2><a class="header" href="#延伸阅读" id="延伸阅读">延伸阅读</a></h2>
<p>关于PRNG的资料非常丰富。<a href="http://www.pcg-random.org/pdf/hmc-cs-2014-0905.pdf">PCG的论文</a>也大都很容易理解，其中也解释了更多的概念。</p>
<p>另一篇关于RNG的高质量论文是 P. Hellekalek 写的[“好的随机数生成器（不是那么）容易找到”]https://web.archive.org/web/20160801142711/http://random.mat.sbg.ac.at/results/peter/A19final.pdf)。</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        
                            <a rel="prev" href="guide-gen.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                        

                        
                            <a rel="next" href="guide-seeding.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                
                    <a rel="prev" href="guide-gen.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a rel="next" href="guide-seeding.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
                
            </nav>

        </div>

        

        

        

        
        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        

        

        
        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
        

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

        

    </body>
</html>
